﻿#include "TaskTime.h"
#include <sys/eventfd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include "common.h"
// #include "log4z.h"

// using namespace zsummer::log4z;
typedef std::lock_guard<std::mutex>  spanlocker;

bool _large(const struct timeval& t1, const struct timeval& t2)
{
    if (t1.tv_sec != t2.tv_sec) return t1.tv_sec > t2.tv_sec;

    return t1.tv_usec > t2.tv_usec;
}

TaskData::TaskData():
    m_taskid(0),
    m_status(0)
{
}

TaskData::~TaskData()
{
}

uint64_t  TaskTimer::GetDataId()
{
    uint32_t  tempVal = m_data_id.load();
    while (!m_data_id.compare_exchange_strong(tempVal, tempVal + 1)) {}

    return (m_unique_id | (tempVal + 1));
}

TaskDataPtr TaskTimer::GetTask(uint64_t taskid)
{
    spanlocker lock(m_spin_lock);

    auto iter = m_task_list.find(taskid);
    if (iter == m_task_list.end()) return NULL;

    return iter->second;
}

TaskTimer::TaskTimer(uint32_t baseid):
    Event(100000)
{
    m_unique_id = ((uint64_t)baseid) << 32;
    m_data_id = 0;
}

TaskTimer::~TaskTimer()
{
}

void TaskTimer::CycleTask()
{
    std::weak_ptr<TaskData> param;
    std::function<void(std::weak_ptr<TaskData>)> func = NULL;
    TimePackerPtr curPack = NULL;
    struct timeval tempTime, curTime;

    long long waitTime = 100000;
    gettimeofday(&curTime, NULL);
    
    while (true)
    {
        {
            spanlocker lock(m_spin_lock);

            auto iter = m_TimeTask.begin();
            if (iter == m_TimeTask.end())
            {
                break;
            }

            if (!_large(curTime, iter->first))
            {
                tempTime = iter->first;

                if (curTime.tv_usec > tempTime.tv_usec)
                {
                    tempTime.tv_sec -= 1;
                    waitTime = tempTime.tv_usec - curTime.tv_usec + 1000000;
                }
                else
                {
                    waitTime = tempTime.tv_usec - curTime.tv_usec;
                }
                waitTime = (tempTime.tv_sec - curTime.tv_sec) * 1000 + waitTime / 1000 + 1;

                break;
            }
            else
            {
                curPack = iter->second;
                iter = m_TimeTask.erase(iter);
            }
        }
        if(curPack)curPack->m_func(curPack->m_param);
        curPack.reset();
    }

    RetSetCycle(waitTime);
}

int TaskTimer::AddTask(
    long long msecond, std::function<void(std::weak_ptr<TaskData>)> m_func, std::weak_ptr<TaskData> param
)
{
    struct timeval curTime = { 0, 0 };
    gettimeofday(&curTime, NULL);
    
    curTime.tv_usec = curTime.tv_usec + msecond * 1000;
    
    if (curTime.tv_usec >= 1000000)
    {
        curTime.tv_sec += curTime.tv_usec / 1000000;
        curTime.tv_usec = curTime.tv_usec % 1000000;
    }

    m_TimeTask.insert({ curTime, TimePackerPtr(new TimePacker(param, m_func)) });
    RetSetCycle();

    if (0 != WakeUpTask())
    {
        m_TimeTask.erase(curTime);
        return -1;
    }
    return 0;
}

int TaskTimer::AddTask(std::shared_ptr<TaskData> param)
{
    if (!param) return -1;

    spanlocker lock(m_spin_lock);

    auto iter = m_task_list.find(param->m_taskid);
    if (iter != m_task_list.end()) return -1;

    m_task_list.insert({ param->m_taskid, param });
    return 0;
}

int TaskTimer::AddTask(
    long long msecond, std::shared_ptr<TaskData> param, std::function<void(std::weak_ptr<TaskData>)> func
)
{
    if (!param) return -1;

    if (NULL == func)
    {
        func = [this](std::weak_ptr<TaskData> param)
        {
            TaskDataPtr my_param = param.lock();
            if (!my_param) return;

            this->DeleteTask(my_param->m_taskid);
        };
    }

    spanlocker lock(m_spin_lock);

    auto iter = m_task_list.find(param->m_taskid);
    if (iter != m_task_list.end()) return -1;

    m_task_list.insert({ param->m_taskid, param });

    if (0 != AddTask(msecond, func, param))
    {
        LOGFMTE("add task fail : task id : %lu", param->m_taskid);
        m_task_list.erase(param->m_taskid);
        return -1;
    }
    return 0;
}

int TaskTimer::DeleteTask(uint64_t taskid)
{
    spanlocker lock(m_spin_lock);

    auto iter = m_task_list.find(taskid);
    if (iter == m_task_list.end())
    {
        return -1;
    }

    m_task_list.erase(iter);
    return 0;
}

